namespace Isolation.TeamFoundationServer
{
	#region #using Directives

	using System;
	using System.Collections.Generic;
	using System.Diagnostics;
	using System.Linq;
	using System.Net;
	using System.Security;
	using System.Xml;

	using Microsoft.TeamFoundation.Build.Client;
	using Microsoft.TeamFoundation.Client;
	using Microsoft.TeamFoundation.Server;
	using Microsoft.TeamFoundation.WorkItemTracking.Client;

	#endregion

	public class TeamFoundationServer : ITeamFoundationServer
	{
		private readonly TfsTeamProjectCollection tfs;

		#region Implementation of ITeamFoundationServer

		public Uri Uri
		{
			[DebuggerStepThrough]
			get { return this.tfs.Uri; }
		}

		public ITfsBuildServer GetBuildServer()
		{
			return new TfsBuildServer((IBuildServer) this.tfs.GetService(typeof(IBuildServer)));
		}

		public ITfsWorkItemStore GetWorkItemStore()
		{
			return new TfsWorkItemStore((WorkItemStore) this.tfs.GetService(typeof(WorkItemStore)));
		}

		/// <summary>
		/// </summary>
		/// <param name = "teamProject"></param>
		/// <returns></returns>
		/// <exception cref = "System.Security.SecurityException" />
		public List<string> GetIterationPaths(string teamProject)
		{
			var list = new List<string>();

			var commonStructure = (ICommonStructureService) this.tfs.GetService(typeof(ICommonStructureService));
			var projectInfo = commonStructure.GetProjectFromName(teamProject);
			var structures = commonStructure.ListStructures(projectInfo.Uri);

			foreach (var nodeInfo in structures.Where(x => x.StructureType == "ProjectLifecycle"))
			{
				var nodeElement = commonStructure.GetNodesXml(new[] {nodeInfo.Uri}, true);
				string pathRoot = nodeElement.ChildNodes[0].Attributes["Path"].Value;

				AddIterationChildNodes(nodeElement.ChildNodes[0].ChildNodes[0], pathRoot, list);
			}

			return list;
		}

		#endregion

		public TeamFoundationServer(Uri serverUri)
			: this(serverUri, null, null)
		{
		}

		public TeamFoundationServer(Uri serverUri, string userName, string password)
		{
			ICredentialsProvider credentialsProvider;
			if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))
			{
				credentialsProvider = new UICredentialsProvider();
			}
			else
			{
				string domain = null;
				var tokens = userName.Split(new[] { '\\' });
				if (tokens.Length == 2)
				{
					domain = tokens.First();
					userName = tokens.Last();
				}

				var credentials = (string.IsNullOrEmpty(domain) ? new NetworkCredential(userName, password) : new NetworkCredential(userName, password, domain));
				credentialsProvider = new CredentialsProvider(credentials);
			}

			this.tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(serverUri, credentialsProvider);
			this.tfs.EnsureAuthenticated();
		}

		private static void AddIterationChildNodes(XmlNode node, string pathRoot, ICollection<string> list)
		{
			if (node == null)
			{
				return;
			}

			foreach (XmlNode childNode in node.ChildNodes)
			{
				AddPathToList(childNode, pathRoot, list);

				AddIterationChildNodes(childNode.ChildNodes[0], pathRoot, list);
			}
		}

		private static void AddPathToList(XmlNode node, string pathRoot, ICollection<string> list)
		{
			if (node.ChildNodes.Count == 0)
			{
				string path = node.Attributes["Path"].Value;
				if (path.StartsWith(pathRoot))
				{
					path = path.Substring(pathRoot.Length);
				}
				list.Add(path);
			}
		}

		#region Implementation of IDisposable

		public void Dispose()
		{
			if (this.tfs != null)
			{
				this.tfs.Dispose();
			}
		}

		#endregion

		#region Nested type: CredentialsProvider

		public class CredentialsProvider : ICredentialsProvider
		{
			private readonly NetworkCredential credentials;

			public CredentialsProvider(NetworkCredential credentials)
			{
				this.credentials = credentials;
			}

			#region ICredentialsProvider Members

			public ICredentials GetCredentials(Uri uri, ICredentials failedCredentials)
			{
				return this.credentials;
			}

			public void NotifyCredentialsAuthenticated(Uri uri)
			{
			}

			#endregion
		}

		#endregion
	}
}